#include "OneParticleTest.h"
#include "TestManager.h"

#include <cassert>
#include <cmath>

using namespace phynet;

const Real OneParticleTest::PARTICLE_STARTING_SPEED = 20.0f;
const Real OneParticleTest::PARTICLE_STARTING_ANGLE_GRAD = 45.0f;
const Real OneParticleTest::PARTICLE_STARTING_MASS = 10.0f;
const Real OneParticleTest::PARTICLE_STARTING_DAMPING = 0.999f;

OneParticleTest::OneParticleTest(TestManager* testManager)
	: Test(testManager)
	, m_gravityFG(math::Vector2(0.0f, -9.81f))
{
	srand(NULL);
	Init();
}

OneParticleTest::~OneParticleTest()
{
}

void OneParticleTest::Init()
{
	m_engine.Init();

	m_nextParticleSpeed = PARTICLE_STARTING_SPEED;
	m_nextParticleAngleGrad = PARTICLE_STARTING_ANGLE_GRAD;
	m_nextParticleMass = PARTICLE_STARTING_MASS;
	m_nextParticleDamping = PARTICLE_STARTING_DAMPING;

	phy::ParticleWorld2D& world = m_engine.GetWorld();

	world.AddParticle(&m_particle);
	world.AddForce(&m_gravityFG);
	world.AddForce(&m_windFG);
	world.AddForceOnParticle(&m_gravityFG, &m_particle);
	world.AddForceOnParticle(&m_windFG, &m_particle);

	Shoot();
}

void OneParticleTest::Shoot()
{
	m_windFG.Set(math::Vector2( (10-rand()%21)/10.0f, (10-rand()%21)/10.0f), (rand()%10)/10.0f);

	const Real angleRad = m_nextParticleAngleGrad * 3.1415926f / 180.0f;
	const math::Vector2 startingVel(m_nextParticleSpeed*cosf(angleRad), m_nextParticleSpeed*sinf(angleRad));
	m_particle.Init(m_nextParticleMass, 0.1f, m_nextParticleDamping, 1.0f, math::Vector2(-15.0f, 0.0f), startingVel); //mass, radius, damping, position, velocity...
}

void OneParticleTest::Render(Renderer& renderer) const
{
	typedef math::Vector2 Vector2;
	typedef phy::Particles2D Particles;

	const phy::ParticleWorld2D& world = m_engine.GetWorld();
	const Real speed = m_testManager->GetSlowMotion();

	// instruction
	char buffer[100];
	sprintf(buffer, "Ciao!! e' passato: %.2f  velocita' %.2fX", world.GetTime(), speed);
	renderer.RenderTextLine(buffer);
	sprintf(buffer, "Mass %.2f (-N/+M)", m_nextParticleMass);
	renderer.RenderTextLine(buffer);
	sprintf(buffer, "Speed %.2f (-V/+B)", m_nextParticleSpeed);
	renderer.RenderTextLine(buffer);
	sprintf(buffer, "Direction %.2f (-C/+X)", m_nextParticleAngleGrad);
	renderer.RenderTextLine(buffer);
	sprintf(buffer, "Damping %.3f (-K/+L)", m_nextParticleDamping);
	renderer.RenderTextLine(buffer);
	sprintf(buffer, "");
	renderer.RenderTextLine(buffer);

	// axis
	renderer.RenderLine(Vector2(-50.0f, 0.0f), Vector2(50.0f, 0.0f));
	renderer.RenderLine(Vector2(0.0f, -50.0f), Vector2(0.0f, 50.0f));

	// cannon
	const Real angleRad = m_nextParticleAngleGrad * 3.1415926f / 180.0f;
	Vector2 direct(cosf(angleRad), sinf(angleRad));
	renderer.RenderLine(Vector2(-15.0f, 0.0f), Vector2(-15.0f, 0.0f) + direct);

	// wind
	renderer.RenderLine(Vector2(0.1f, 0.1f), Vector2(0.1f, 0.1f) + m_windFG.GetBaseWindForce()*5.0f);

	// world
	const Particles& particles = world.GetParticles();
	for (Particles::const_iterator i = particles.begin(); i != particles.end(); ++i)
		renderer.RenderCircle((*i)->GetPosition(), (*i)->GetRadius(), 12);
}

void OneParticleTest::Update(float i_elapsedTime)
{
	m_engine.Update(i_elapsedTime);
}

void OneParticleTest::OnKeyPressed(int keyCode)
{
	if (keyCode == sf::Key::S)
	{
		Shoot();
	}
	else if (keyCode == sf::Key::X)
	{
		m_nextParticleAngleGrad += 1.0f;
	}
	else if (keyCode == sf::Key::C)
	{
		m_nextParticleAngleGrad -= 1.0f;
	}
	else if (keyCode == sf::Key::M)
	{
		m_nextParticleMass *= 1.1f;
	}
	else if (keyCode == sf::Key::N)
	{
		m_nextParticleMass /= 1.1f;
	}
	else if (keyCode == sf::Key::B)
	{
		m_nextParticleSpeed += 1.0f;
	}
	else if (keyCode == sf::Key::V)
	{
		m_nextParticleSpeed -= 1.0f;
	}
	else if (keyCode == sf::Key::L)
	{
		if(math::LessThan(m_nextParticleDamping,1.0f))
			m_nextParticleDamping += 0.001f;
	}
	else if (keyCode == sf::Key::K)
	{
		m_nextParticleDamping -= 0.001f;
	}
}
